package team6.gamegui;
import java.util.*;

import team6.AI.Player;

/**
 * Contains all the information of the Othello game state.
 * Is cloned repeatedly when used by AI's to preserve original state.
 * 
 * 
 * 
 * @author Drew Havard
 * @author Drew Reagan
 */
public class GameState implements Cloneable{
	/**
	 * Two dimensional representation of the board in row, column form and zero indexed
	 */
	Vector<Vector<Player>> game;
	/**
	 * Vector of all possible moves for player who moves next
	 */
	Vector<int[]> possibleMoves;
	/**
	 * The player who is moving next. Player.BLACK by static initialization
	 */
    Player turn = Player.BLACK;
    /**
     * Number of "player", or Player.BLACK, pieces.  Statically initialized to 2
     */
    int plPieces=2;
    /**
     * Number of "opponent", or Player.WHITE, pieces.  Statically initialized to 2
     */
    int oppPieces=2;
    /**
     * Name of the opponent, or Player.WHITE
     */
    String oppName;
    /**
     * Name of the player, or Player.BLACK
     */
    String plName;
    /**
     * The last move in the form row, column
     * Initialized to 0,0 by default array behavior
     * The move positions are zero indexed
     */
    int[] lastMove;
    
    /**
     * Increments the given player's pieces
     * @param p	Player to increment
     */
    public void incPieces(Player p) {
        if (p == Player.BLACK)
            plPieces++;
        else
            oppPieces++;
    }
    
    /**
     * Returns "player", or Player.BLACK, name
     * @return plName class member
     */
    public String getPlayerName(){
    	return plName;
    }
    
    /**
     * Returns "opponent", or Player.WHITE, name
     * @return	oppName class member
     */
    public String getOppName(){
    	return oppName;
    }
    
    /**
     * Given a certain move in {row, column}, sets turn to the piece at that location.
     * This is required because makeMove() only takes in boardState and last move-no
     * other way to set turn
     * @param move The {row, column} form of the color/Player to set to turn
     */
    public void setPlayer(int[] move){
    	if(game.get(move[0]).get(move[1])==turn)
    		switchTurn();
    }
    
    /**
     * For the player who just move (the opposite of turn), return the
     * number of corners possessed - the number of opponent possessed corners.
     * @return Number of possessed corners for player who just moved - other player's corners.
     */
    public int numCorners(){
    	int numCorners=0;
    	Player caller;
    	if(turn == Player.BLACK)
    		caller = Player.WHITE;
    	else
    		caller  = Player.BLACK;
    	if(game.get(7).get(7) == caller)
    		++numCorners;
    	else if (game.get(7).get(7) != Player.EMPTY)
    		--numCorners;
    	if(game.get(0).get(0) == caller)
    		++numCorners;
    	else if (game.get(0).get(0) != Player.EMPTY)
    		--numCorners;
    	if(game.get(0).get(7) == caller)
    		++numCorners;
    	else if (game.get(0).get(7) != Player.EMPTY)
    		--numCorners;
    	if(game.get(7).get(0) == caller)
    		++numCorners;
    	else if (game.get(7).get(0) != Player.EMPTY)
    		--numCorners;
    	return numCorners;
    }
    
    
    /**
     * Return which player will move next
     * @return turn class member
     */
    public Player currentPlayer(){
    	return turn;
    }
    
    /**
     * Decrement pieces for the given player
     * @param p Player to decrement pieces for.
     */
    public void decPieces(Player p) {
        if (p==Player.BLACK)
            plPieces--;
        else
            oppPieces--;
    }
    
    /**
     * Returns whether or not there are possibleMoves that have been
     * calculated.  Will return a (logically) false true if calculateMoves()
     * has not been called.
     * @return Whether or not there are any moves in possibleMoves()
     */
    public boolean existMoves() {
        return possibleMoves.size()>0;
    }
    
    /**
     * Returns the last move in {row, column} form.
     * @return lastMove class member.
     */
    public int[] getLastMove(){
    	return lastMove;
    }
    
    /**
     * Returns either the winning player's color, the string "TIE" if
     * the game is tied, and "" if the game is not over
     * @return Either "Black" if Player.BLACK wins.
     * "White" if Player.WHITE wins.
     * "TIE" if the game is tied.
     * "" if the game is not over.
     */
    public String gameOver() {
    	Vector<int[]> currentMoves = possibleMoves;
        if (!existMoves()) {
            switchTurn();
            calculateMoves();
            if (!existMoves()) {
                if (plPieces>oppPieces)
                    return "Black";
                else if (oppPieces>plPieces)
                    return "White";
                else
                    return "TIE";
            } else {
                switchTurn();
                possibleMoves = currentMoves;
            }
        }

        return "";
    }
    
    /**
     * Returns whether or not the player who should move next needs to pass
     * @return true if the player who could move next needs to pass, false if the player does not need to pass
     */
    public boolean needsToPass() {
        if (!existMoves()) {
            switchTurn();
            calculateMoves();
            if (existMoves()) {
                switchTurn();
                return true;
            } else {
                switchTurn();
                return false;
            }
        }
        return false;
    }

    /**
     * Contains the directions in which pieces are taken.  Directions
     * are set by accessing the member variables.
     * 
     * @author Drew Havard
     * @author Drew Reagan
     */
    private class FlipDirs {
        protected boolean north;
        protected boolean northeast;
        protected boolean east;
        protected boolean southeast;
        protected boolean south;
        protected boolean southwest;
        protected boolean west;
        protected boolean northwest;

        /**
         * Initializes all directions to false
         */
        public FlipDirs() {
            north = false;
            northeast = false;
            east = false;
            southeast = false;
            south = false;
            southwest = false;
            west = false;
            northwest = false;
        }

        /**
         * If there is any direction that pieces can be taken in returns true
         * @return Whether or not pieces can be taken
         */
        public boolean existValidMoves() {
            return north || northeast || east || southeast || south || southwest || west || northwest;
        }
    }

	/**
	 * Constructs game Vector from boardState performing a deep copy.  All members are initialized but players' names
	 * but only game and lastMove are set to given values.
	 * 
	 * @param boardState The layout of pieces on the board, which will be copied deeply
	 * @param inLastMove The {row, column} form of the last move.
	 */
	public GameState(Player[][] boardState, int[] inLastMove){
        game = new Vector<Vector<Player>>();
        possibleMoves = new Vector<int[]>();
        lastMove = inLastMove.clone();
        setState(boardState);
	}	
	/**
	 * Used in cloning.  Performs deep copy of inGame.  Only game and lastMove are set.  possibleMoves 
	 * is also initialized.
	 * @param inGame	The layout of pieces on the board, which will be copied deeply
	 * @param inLastMove The {row, column} form of the last move.
	 */
	public GameState(Vector<Vector<Player>> inGame, int[] inLastMove){
        game = new Vector<Vector<Player>>();
        possibleMoves = new Vector<int[]>();
        lastMove = inLastMove.clone();
		setState(inGame);
    }

	/**
	 * Initializes all variables but the players' names, but unless they are statically set
	 * does not change them.
	 */
    public GameState(){
        game = new Vector<Vector<Player>>();
        possibleMoves = new Vector<int[]>();
        lastMove = new int[2];
	}
    
    /**
     * Performs a deep copy of boardState to game
     * @param boardState Layout of pieces to be deeply copied
     */
    public void setState(Vector<Vector<Player>> boardState) {
        game.clear();

        for (int j=0; j<boardState.size(); j++) {
            Vector<Player> rowVec = new Vector<Player>();
            for (int i=0; i<boardState.size(); i++) {
                rowVec.add(boardState.get(j).get(i));
            }
            game.add(rowVec);
        }
    }

    /**
     * Performs a deep copy of boardState to game
     * @param boardState Layout of pieces to be deeply copied
     */
    public void setState(Player[][] boardState) {
        game.clear();

        for (int j=0; j<boardState.length; j++) {
            Vector<Player> rowVec = new Vector<Player>();
            for (int i=0; i<boardState.length; i++)
                rowVec.add(boardState[j][i]);
            game.add(rowVec);
        }
    }
	
    /**
     * Deeply copies the calling object and returns it.  Must be cast to be used as a GameState
     */
	public Object clone(){
    	GameState toRet =  new GameState((Vector<Vector<Player>>)game.clone(), this.lastMove);
    	toRet.possibleMoves = (Vector<int[]>) this.possibleMoves.clone();
    	toRet.plPieces = this.plPieces;
    	toRet.oppName = this.oppName;
    	toRet.turn=this.turn;
    	toRet.oppName = this.oppName;
    	toRet.plName = this.plName;
    	return toRet;
	}
	
	/**
	 * Returns a deep copy of game as a 2d array of form Player[row][column]
	 * @return 2d array in [row][column] form from a deep copy of game
	 */
	public Player[][] parse(){
        Player[][] gameArray = new Player[8][8];
        for(int i = 0; i < 8; ++i)
        	gameArray[i] = game.get(i).toArray(gameArray[i]);
		return gameArray;
	}
	
	/**
	 * For whichever player is turn, sets the that piece at the given
	 * coordinates if the move is valid.  Uses validMove to know which the pieces are
	 * necessary to flip if the move is valid.  Calls flipPieces to flip the pieces
	 * between this move and all opponent pieces.  Returns true if move is valid and false otherwise.
	 * 
	 * This method also uses static GameGUI methods to update the GUI state.
	 * 
	 * @param row Row of position to set to player turn
	 * @param column Column of position to set to player turn
	 * @return True if move is valid, false if move is invalid
	 */
	public boolean move(int row, int column){
        FlipDirs flips = validMove(row, column);
		if(!flips.existValidMoves())
			return false;
		game.get(row).set(column, turn);
        flipPieces(row, column, flips, turn);
        incPieces(turn);
        lastMove[0] = row;
        lastMove[1] = column;
        GameGui.changeButton(row, column, turn);
		return true;
	}

	/**
	 * For whichever player is turn, sets the that piece at the given
	 * coordinates if the move is valid.  Uses validMove to know which the pieces are
	 * necessary to flip if the move is valid.  Calls flipPieces to flip the pieces
	 * between this move and all opponent pieces.  Returns true if move is valid and false otherwise.
	 * 
	 * This method does not interact with the GUI.
	 * 
	 * @param row Row of position to set to player turn
	 * @param column Column of position to set to player turn
	 * @return True if move is valid, false if move is invalid
	 */
    public boolean moveNoGui(int row, int column){
        FlipDirs flips = validMove(row, column);
		if(!flips.existValidMoves())
			return false;
		game.get(row).set(column, turn);
        flipPiecesNoGui(row, column, flips, turn);
        incPieces(turn);
        lastMove[0] = row;
        lastMove[1] = column;
        return true;
	}
    
    /**
     * Given the {row, column} of a move, creates a FlipDirs that represents the
     * directions in which there are pieces to be taken for the current player (signified
     * by turn).
     * @param row Row of the move to be tested
     * @param column Column of the move to be tested
     * @return FlipDirs containing information of direction of pieces to be taken.
     */
	private FlipDirs validMove(int row, int column){
        int maxVal = GameGui.boardDim;
        FlipDirs dirs = new FlipDirs();

        // theoretically not possible, but check anyway
        if (row<0 || column<0 || row>=maxVal || column>=maxVal)
            return dirs;
        
        if (game.get(row).get(column)!=Player.EMPTY)
            return dirs;

        boolean oppPassed = false;
        Player empty = Player.EMPTY;
        Player opponent = Player.BLACK;
        if (turn==Player.BLACK)
            opponent = Player.WHITE;

        // check North
        if (row>0 && game.get(row-1).get(column)==opponent) {
            for (int y=row-1; y>=0; y--) {
                if (oppPassed && game.get(y).get(column)==turn) {
                    dirs.north=true;
                    break;
                }
                if (game.get(y).get(column)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(column)==empty)
                    break;
            }
            oppPassed = false;
        }
        
        // check NorthEast
        if (row>0 && column<maxVal-1 && game.get(row-1).get(column+1)==opponent) {
            for (int y=row-1, x=column+1; y>=0 && x<=maxVal-1; y--,x++) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    dirs.northeast=true;
                    break;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;

            }
            oppPassed = false;
        }
        
        // check East
        if (column<maxVal-1 && game.get(row).get(column+1)==opponent) {
            for (int x=column+1; x<=maxVal-1; x++) {
                if (oppPassed && game.get(row).get(x)==turn) {
                    dirs.east=true;
                    break;
                }
                if (game.get(row).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(row).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }
        
        // check SouthEast
        if (row<maxVal-1 && column<maxVal-1 && game.get(row+1).get(column+1)==opponent) {
            for (int y=row+1, x=column+1; y<=maxVal-1 && x<=maxVal-1; y++,x++) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    dirs.southeast=true;
                    break;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check South
        if (row<maxVal-1 && game.get(row+1).get(column)==opponent) {
            for (int y=row+1; y<=maxVal-1; y++) {
                if (oppPassed && game.get(y).get(column)==turn) {
                    dirs.south=true;
                    break;
                }
                if (game.get(y).get(column)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(column)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check SouthWest
        if (row<maxVal-1 && column>0 && game.get(row+1).get(column-1)==opponent) {
            for (int y=row+1, x=column-1; y<=maxVal-1 && x>=0; y++,x--) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    dirs.southwest=true;
                    break;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check West
        if (column>0 && game.get(row).get(column-1)==opponent) {
            for (int x=column-1; x>=0; x--) {
                if (oppPassed && game.get(row).get(x)==turn) {
                    dirs.west=true;
                    break;
                }
                if (game.get(row).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(row).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check NorthWest
        if (row>0 && column>0 && game.get(row-1).get(column-1)==opponent) {
            for (int y=row-1, x=column-1; y>=0 && x>=0; y--,x--) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    dirs.northwest=true;
                    break;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        return dirs;
	}
	
	/**
	 * Returns whether or not the move is valid.
	 * 
	 * @param row Row of the move to be tested
	 * @param column Column of the move to be tested
	 * @return Returns whether or not the move is valid
	 */
	private boolean validMoveNoFlips(int row, int column){
        int maxVal = GameGui.boardDim;
        // theoretically not possible, but check anyway
        if (row<0 || column<0 || row>=maxVal || column>=maxVal)
            return false;
        else if (game.get(row).get(column)!=Player.EMPTY)
            return false;
        
        boolean oppPassed = false;
        Player empty = Player.EMPTY;
        Player opponent = Player.BLACK;
        if (turn==Player.BLACK)
            opponent = Player.WHITE;

        // check North
        if (row>0 && game.get(row-1).get(column)==opponent) {
            for (int y=row-1; y>=0; y--) {
                if (oppPassed && game.get(y).get(column)==turn) {
                    return true;
                }
                if (game.get(y).get(column)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(column)==empty)
                    break;
            }
            oppPassed = false;
        }
        
        // check NorthEast
        if (row>0 && column<maxVal-1 && game.get(row-1).get(column+1)==opponent) {
            for (int y=row-1, x=column+1; y>=0 && x<=maxVal-1; y--,x++) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    return true;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;

            }
            oppPassed = false;
        }
        
        // check East
        if (column<maxVal-1 && game.get(row).get(column+1)==opponent) {
            for (int x=column+1; x<=maxVal-1; x++) {
                if (oppPassed && game.get(row).get(x)==turn) {
                    return true;
                }
                if (game.get(row).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(row).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }
        
        // check SouthEast
        if (row<maxVal-1 && column<maxVal-1 && game.get(row+1).get(column+1)==opponent) {
            for (int y=row+1, x=column+1; y<=maxVal-1 && x<=maxVal-1; y++,x++) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    return true;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check South
        if (row<maxVal-1 && game.get(row+1).get(column)==opponent) {
            for (int y=row+1; y<=maxVal-1; y++) {
                if (oppPassed && game.get(y).get(column)==turn) {
                    return true;
                }
                if (game.get(y).get(column)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(column)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check SouthWest
        if (row<maxVal-1 && column>0 && game.get(row+1).get(column-1)==opponent) {
            for (int y=row+1, x=column-1; y<=maxVal-1 && x>=0; y++,x--) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    return true;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check West
        if (column>0 && game.get(row).get(column-1)==opponent) {
            for (int x=column-1; x>=0; x--) {
                if (oppPassed && game.get(row).get(x)==turn) {
                    return true;
                }
                if (game.get(row).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(row).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        // check NorthWest
        if (row>0 && column>0 && game.get(row-1).get(column-1)==opponent) {
            for (int y=row-1, x=column-1; y>=0 && x>=0; y--,x--) {
                if (oppPassed && game.get(y).get(x)==turn) {
                    return true;
                }
                if (game.get(y).get(x)==opponent)
                    oppPassed = true;
                else if (game.get(y).get(x)==empty)
                    break;
            }
            oppPassed = false;
        }

        return false;
	}
    
	/**
	 * With the given player will calculate all the moves that player can
	 * make and put them in possibleMoves
	 */
	public void calculateMoves(){
        possibleMoves.clear();

		for (int row=0; row<GameGui.boardDim; row++)
            for (int col=0; col<GameGui.boardDim; col++) {
                if (validMoveNoFlips(row,col)) {
                    int[] move = {row, col};
                    possibleMoves.add(move);
                }
            }
	}
	
	/**
	 * Will flip all of the pieces between {row, column} and the direction given by dir
	 * until a AI.Player is encountered that is the opposite color of the given player.
	 * 
	 * This will also change the GUI through static GUI methods
	 * @param row	The row of the initial position
	 * @param column	The column of the initial position
	 * @param dir	The direction(s) that opponent's pieces lie to be taken
	 * @param player	The player who is taking pieces
	 */
    private void flipPieces(int row, int column, FlipDirs dir, Player player) {
        Player opponent = (player==Player.BLACK)?Player.WHITE:Player.BLACK;

        // North
        if (dir.north)
            for(int y=row-1; game.get(y).get(column)!=player; y--) {
                game.get(y).setElementAt(player, column);
                GameGui.changeButton(y, column, player);
                incPieces(player);
                decPieces(opponent);
            }

        // NorthEast
        if (dir.northeast)
            for(int y=row-1, x=column+1; game.get(y).get(x)!=player; y--,x++) {
                game.get(y).setElementAt(player, x);
                GameGui.changeButton(y, x, player);
                incPieces(player);
                decPieces(opponent);
            }

        // East
        if (dir.east)
            for(int x=column+1; game.get(row).get(x)!=player; x++) {
                game.get(row).setElementAt(player, x);
                GameGui.changeButton(row, x, player);
                incPieces(player);
                decPieces(opponent);
            }

        // SouthEast
        if (dir.southeast)
            for(int y=row+1, x=column+1; game.get(y).get(x)!=player; y++,x++) {
                game.get(y).setElementAt(player, x);
                GameGui.changeButton(y, x, player);
                incPieces(player);
                decPieces(opponent);
            }

        // South
        if (dir.south)
            for(int y=row+1; game.get(y).get(column)!=player; y++) {
                game.get(y).setElementAt(player, column);
                GameGui.changeButton(y, column, player);
                incPieces(player);
                decPieces(opponent);
            }

        // SouthWest
        if (dir.southwest)
            for(int y=row+1, x=column-1; game.get(y).get(x)!=player; y++,x--) {
                game.get(y).setElementAt(player, x);
                GameGui.changeButton(y, x, player);
                incPieces(player);
                decPieces(opponent);
            }

        // West
        if (dir.west)
            for (int x=column-1; game.get(row).get(x)!=player; x--) {
                game.get(row).setElementAt(player, x);
                GameGui.changeButton(row, x, player);
                incPieces(player);
                decPieces(opponent);
            }

        // NorthWest
        if (dir.northwest)
            for (int y=row-1, x=column-1; game.get(y).get(x)!=player; y--,x--) {
                game.get(y).setElementAt(player, x);
                GameGui.changeButton(y, x, player);
                incPieces(player);
                decPieces(opponent);
            }
    }

    /**
	 * Will flip all of the pieces between {row, column} and the direction given by dir
	 * until a AI.Player is encountered that is the opposite color of the given player.
	 * 
	 * @param row	The row of the initial position
	 * @param column	The column of the initial position
	 * @param dir	The direction(s) that opponent's pieces lie to be taken
	 * @param player	The player who is taking pieces
	 */
    private void flipPiecesNoGui(int row, int column, FlipDirs dir, Player player) {
        Player opponent = (player==Player.BLACK)?Player.WHITE:Player.BLACK;

        // North
        if (dir.north)
            for(int y=row-1; game.get(y).get(column)!=player; y--) {
                game.get(y).setElementAt(player, column);
                incPieces(player);
                decPieces(opponent);
            }

        // NorthEast
        if (dir.northeast)
            for(int y=row-1, x=column+1; game.get(y).get(x)!=player; y--,x++) {
                game.get(y).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }

        // East
        if (dir.east)
            for(int x=column+1; game.get(row).get(x)!=player; x++) {
                game.get(row).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }

        // SouthEast
        if (dir.southeast)
            for(int y=row+1, x=column+1; game.get(y).get(x)!=player; y++,x++) {
                game.get(y).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }

        // South
        if (dir.south)
            for(int y=row+1; game.get(y).get(column)!=player; y++) {
                game.get(y).setElementAt(player, column);
                incPieces(player);
                decPieces(opponent);
            }

        // SouthWest
        if (dir.southwest)
            for(int y=row+1, x=column-1; game.get(y).get(x)!=player; y++,x--) {
                game.get(y).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }

        // West
        if (dir.west)
            for (int x=column-1; game.get(row).get(x)!=player; x--) {
                game.get(row).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }

        // NorthWest
        if (dir.northwest)
            for (int y=row-1, x=column-1; game.get(y).get(x)!=player; y--,x--) {
                game.get(y).setElementAt(player, x);
                incPieces(player);
                decPieces(opponent);
            }
    }

    /**
     * Switches the turn and returns who's turn it is after the change.
     * Also set's whether or not the GUI should be listening for user input: while the computer is
     * working the GUI does not need to be listening.  Also calculates turns so that the possibleMoves
     * is current.
     * @return A string representing the turn. In form (Color) name's Turn
     */
    public String switchTurn() {
        if (turn==Player.BLACK) {
            turn=Player.WHITE;
            calculateMoves();
            if (GameGui.numPlayers <2)
            	GameGui.listen.set(false);
            return "(White) " + oppName + "'s Turn";
        }
        else {
            turn=Player.BLACK;
            calculateMoves();
            if(GameGui.numPlayers>0)
            	GameGui.listen.set(true);
            return "(Black) " + plName + "'s Turn";
        }
    }
    
    /**
     * Switches the turn and returns who's turn it is after the change.
     * Also set's whether or not the GUI should be listening for user input: while the computer is
     * working the GUI does not need to be listening.  Does NOT calculate the new possible moves.
     * Used in recursion where the child calculates it's own moves
     * @return A string representing the turn. In form (Color) name's Turn
     */
    public String switchTurnNoCalc() {
        if (turn==Player.BLACK) {
            turn=Player.WHITE;
            if (GameGui.numPlayers <2)
            	GameGui.listen.set(false);
            return "(White) " + oppName + "'s Turn";
        }
        else {
            turn=Player.BLACK;
            if(GameGui.numPlayers>0)
            	GameGui.listen.set(true);
            return "(Black) " + plName + "'s Turn";
        }
    }
    
    /**
     * Returns whoever is about to move's number of pieces
     * @return Number of pieces for the player about to move
     */
	public int numPiecesCurrentPlayer() {
		// TODO Auto-generated method stub
		if(turn == Player.BLACK)
			return oppPieces;
		else
			return plPieces;
	}
	
	/**
	 * Returns a vector of int[] in the form of {row, column} for all players
	 * @return possibleMoves member variable
	 */
	public Vector<int[]> possibleMoves() {
		// TODO Auto-generated method stub
		return possibleMoves;
	}
	
	/**
	 * Return's the number of Player.WHITE pieces
	 * @return oppPieces member variable
	 */
    public int numWhite() {
        return oppPieces;
    }

    /**
     * Return the number of Player.BLACK pieces
     * @return plPieces member variable
     */
    public int numBlack() {
        return plPieces;
    }

    /**
     * Returns the total number of pieces for both players.
     * Does not simply total plPieces and oppPieces, actually iterates through
     * the board and sums all non Player.EMPTY locations.
     * @return Number of total pieces
     */
    public int numTotPieces() {
        int toRet=0;
        for(Vector<Player> g: game){
            for(Player p: g)
                if(p==Player.BLACK || p==Player.WHITE)
                    toRet++;
        }
        return toRet;
    }
}
